package crazymakercircle;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @Author: DRevelation
 * @Date: 2021/10/9 15:14
 */
@Slf4j
public class NioReceiveServer {
    private static final String RECEIVE_PATH = "";

    private Charset charset = StandardCharsets.UTF_8;

    /**
     * 服务器端保存的客户端对象，对应一个客户端文件
     */
    static class Client {
        String fileName;
        long fileLength;
        long startTime;
        InetSocketAddress remoteAddress;
        FileChannel outChannel;
        long receiveLength;

        public boolean isFinished() {
            return receiveLength >= fileLength;
        }
    }

    private ByteBuffer buffer = ByteBuffer.allocate(1024);

    /**
     * 使用Map保存每个客户端传输
     * 当OP_READ通道可读时，根据channel找到对应的对象
     */
    Map<SelectableChannel, Client> clientMap = new HashMap<>();

    /**
     * 启动服务 —— Selector与Channel
     * @throws IOException
     */
    public void startServer() throws IOException {
        Selector selector = Selector.open();

        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);
        InetSocketAddress address = new InetSocketAddress(18899);
        serverChannel.bind(address);

        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        log.info("serverChannel is listening...");
        // 轮询感兴趣的I/O就绪时间（选择键集合）
        while (selector.select() > 0) {
            Iterator<SelectionKey> it = selector.selectedKeys().iterator();
            while (it.hasNext()) {
                SelectionKey key = it.next();
                //判断key是否为新连接事件
                if (key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    SocketChannel socketChannel = server.accept();
                    if (socketChannel == null) {
                        continue;
                    }
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    //余下业务处理
                    Client client = new Client();
                    client.remoteAddress = (InetSocketAddress) socketChannel.getRemoteAddress();
                    clientMap.put(socketChannel, client);
                    log.info(socketChannel.getRemoteAddress() + "连接成功...");
                } else if (key.isReadable()) {
                    processData(key);
                }
                //NIO的特点只会累加，已选择的键的集合不会删除
                //如果不删除，下一次又会被select函数选中
                it.remove();
            }
        }
    }

    /**
     * 处理客户端传来的数据 —— Buffer
     * @param key
     */
    private void processData(SelectionKey key) {

    }
}
